#include "FlowChart.h"
#include "ProxyEventHandlerImpl.h"
#include "Proxy.h"
#include "GateServerRoot.h"
#include "SessionValidator.h"
#include "EndianCast.h"
#include "../../include/GTProto.h"
#include <ut_debug.h>
#pragma comment(lib, "logutil.lib")
/************************************************************************/
/* Machine                                                              */
/************************************************************************/
void Machine::SendPipeMsg( utility::network::PIPEID pipeID, void * message, size_t message_length , bool isForward ) const
{
    if(m_pProxyEventHandler && pipeID.number != 0)
    {
        if (CProxy * pProxy = m_pProxyEventHandler->GetProxy())
            pProxy->SendPipeMsg(pipeID, message, message_length, isForward);
    }
}

void Machine::SendClientMsg( void * message, size_t message_length ) const
{
    if(m_pProxyEventHandler)
    {
        if (CProxy * pProxy = m_pProxyEventHandler->GetProxy())
            pProxy->SendClientMsg(message, message_length);
    }
}

void Machine::SendServerMsg( void * message, size_t message_length ) const
{
    if(m_pProxyEventHandler)
    {
        if (CProxy * pProxy = m_pProxyEventHandler->GetProxy())
            pProxy->SendServerMsg(message, message_length);
    }
}

void Machine::Disconnect()
{
    if (m_pProxyEventHandler)
    {
        if (CProxy * pProxy = m_pProxyEventHandler->GetProxy())
            pProxy->Disconnect();
    }
}

Machine::Machine( CProxyEventHandler * pHandler)
{
    m_pProxyEventHandler = pHandler;
}

CProxy * Machine::GetProxy()
{
    if (m_pProxyEventHandler)
        return m_pProxyEventHandler->GetProxy();
    return NULL;
}

/************************************************************************/
/*  DBCommState                                                         */
/************************************************************************/
DBCommState::DBCommState()
{
    LOG(DEBUGINFO) << __FUNCTION__;
    m_tStartTime = time(NULL);
    CMinuteTimer::Instance()->Subscribe(this);
}

DBCommState::~DBCommState()
{
    LOG(DEBUGINFO) << __FUNCTION__;
    CMinuteTimer::Instance()->UnSubscribe(this);
}

void DBCommState::OnRcvCliMessage( const char * message, uint32 message_length ) const
{
    context<Machine>().SendPipeMsg(GateServerRoot::Instance()->GetDBServerPipeId(), (void *)message, message_length);
}

void DBCommState::OnRcvPipeMessage(utility::network::PIPEID pipeID, const char * message, uint32 message_length ) const
{
    context<Machine>().SendClientMsg((void *)message, message_length);
}

void DBCommState::OnTrigger( time_t tNow)
{
    if (tNow - m_tStartTime > 600)
    {
        context<Machine>().Disconnect();
    }
}

/************************************************************************/
/* GSCommState                                                          */
/************************************************************************/
GSCommState::GSCommState()
{
    LOG(DEBUGINFO) << __FUNCTION__;
}

GSCommState::~GSCommState()
{
    LOG(DEBUGINFO) << __FUNCTION__;
}

void GSCommState::OnRcvCliMessage( const char * message, uint32 message_length ) const
{
    context<Machine>().SendServerMsg((void *)message, message_length);
}

void GSCommState::OnRcvSvrMessage( const char * message, uint32 message_length ) const
{
    context<Machine>().SendClientMsg((void *)message, message_length);
}

/************************************************************************/
/* ValidateState                                                        */
/************************************************************************/
ValidateState::ValidateState()
{
    LOG(DEBUGINFO) << __FUNCTION__;
    m_tStartTime = time(NULL);
    m_nFailTimes = 0;
    CMinuteTimer::Instance()->Subscribe(this);
}

ValidateState::~ValidateState()
{
    LOG(DEBUGINFO) << __FUNCTION__;
    CMinuteTimer::Instance()->UnSubscribe(this);
}

void ValidateState::OnRcvCliMessage( const char * message, uint32 message_length ) const
{
    uint32 nProtoID = ntohl(*(uint32 *)message);
    if (nProtoID == GT_USER_VALIDATE_REQ_ID)
    {
        GT_USER_VALIDATE_REQ_PKG * pkg = (GT_USER_VALIDATE_REQ_PKG *)(message + sizeof(nProtoID));
        if (CSessionValidator::Instance()->IsValid(
            ntohl(pkg->nUserID),
            ntohl(pkg->nToken)
            ))
        {
            const_cast<ValidateState*>(this)->OnValidate(ntohl(pkg->nUserID), ntohl(pkg->nToken));
            return;
        }
    }
    const_cast<ValidateState *>(this)->OnFailValidate();
    
}

void ValidateState::OnTrigger( time_t tNow)
{
    if(tNow - m_tStartTime > 600)
    {
        context<Machine>().Disconnect();
    }
}

void ValidateState::OnValidate(uint32 nUsrID, uint32 nToken)
{
    LOG(DEBUGINFO) << __FUNCTION__;
    if (CProxy * pProxy = context<Machine>().GetProxy())
    {
        pProxy->SetUserID(nUsrID);
        {
            char buf[sizeof(uint32) + sizeof(GT_NOTIFY_USER_ONLINE_NTF_PKG)] = {0};
            *(uint32*)buf = htonl(GT_NOTIFY_USER_ONLINE_NTF_ID);
            GT_NOTIFY_USER_ONLINE_NTF_PKG * pkg = (GT_NOTIFY_USER_ONLINE_NTF_PKG *)(buf + sizeof(uint32));
            pkg->nUserID = htonl(pProxy->GetUserID());
            pkg->nProxyID = htonll(pProxy->GetID());
            pkg->nToken = htonl(nToken);
            context<Machine>().SendPipeMsg(GateServerRoot::Instance()->GetDBServerPipeId(), buf, sizeof(buf), false);
        }
        {
            char buf[sizeof(uint32) + sizeof(GT_USER_VALIDATE_ACK_PKG)] = {0};
            *(uint32*)buf = htonl(GT_USER_VALIDATE_ACK_ID);
            GT_USER_VALIDATE_ACK_PKG * pkg = (GT_USER_VALIDATE_ACK_PKG *)(buf + sizeof(uint32));
            pkg->error_code = 0;
            context<Machine>().SendClientMsg((void*)buf, sizeof(buf));
        }
        context<Machine>().process_event(EvValidated());
    }

}

void ValidateState::OnFailValidate()
{
    LOG(DEBUGINFO) << __FUNCTION__;
    if(++m_nFailTimes == 2)
        context<Machine>().Disconnect();

    char buf[sizeof(uint32) + sizeof(GT_USER_VALIDATE_ACK_PKG)] = {0};
    *(uint32*)buf = htonl(GT_USER_VALIDATE_ACK_ID);
    GT_USER_VALIDATE_ACK_PKG * pkg = (GT_USER_VALIDATE_ACK_PKG *)(buf + sizeof(uint32));
    pkg->error_code = 1;
    context<Machine>().SendClientMsg((void*)buf, sizeof(buf));
}

